﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Shapes;

namespace ICodeShare.UI.Controls
{
    /// <summary>
    /// Root Grid
    /// </summary>
    [TemplatePart(Name = PART_RootGrid, Type = typeof(Grid))]
    [TemplatePart(Name = PART_THLPath, Type = typeof(Path))]
    [TemplatePart(Name = PART_THRPath, Type = typeof(Path))]
    [TemplatePart(Name = PART_TVLPath, Type = typeof(Path))]
    [TemplatePart(Name = PART_TVMPath, Type = typeof(Path))]
    [TemplatePart(Name = PART_TVRPath, Type = typeof(Path))]
    [TemplatePart(Name = PART_MHLPath, Type = typeof(Path))]
    [TemplatePart(Name = PART_MHRPath, Type = typeof(Path))]
    [TemplatePart(Name = PART_BVLPath, Type = typeof(Path))]
    [TemplatePart(Name = PART_BVMPath, Type = typeof(Path))]
    [TemplatePart(Name = PART_BVRPath, Type = typeof(Path))]
    [TemplatePart(Name = PART_BHLPath, Type = typeof(Path))]
    [TemplatePart(Name = PART_BHRPath, Type = typeof(Path))]
    [TemplatePart(Name = PART_TDLPath, Type = typeof(Path))]
    [TemplatePart(Name = PART_TDRPath, Type = typeof(Path))]
    [TemplatePart(Name = PART_BDLPath, Type = typeof(Path))]
    [TemplatePart(Name = PART_BDRPath, Type = typeof(Path))]
    public class SixteenSegmentDigit : ContentControl
    {
        #region Constants

        //模板上关键元素
        private const string PART_RootGrid = "PART_RootGrid"; //主要部分

        private const string PART_THLPath = "PART_THLPath"; //主要部分-上水平左  1
        private const string PART_THRPath = "PART_THRPath"; //主要部分-上水平右  2
        private const string PART_TVLPath = "PART_TVLPath"; //主要部分-上竖直左  3
        private const string PART_TVMPath = "PART_TVMPath"; //主要部分-上竖直中  4
        private const string PART_TVRPath = "PART_TVRPath"; //主要部分-上竖直右  5
        private const string PART_MHLPath = "PART_MHLPath"; //主要部分-中水平左  6
        private const string PART_MHRPath = "PART_MHRPath"; //主要部分-中水平右  7
        private const string PART_BVLPath = "PART_BVLPath"; //主要部分-下竖直左  8
        private const string PART_BVMPath = "PART_BVMPath"; //主要部分-下竖直中  9
        private const string PART_BVRPath = "PART_BVRPath"; //主要部分-下竖直右  10
        private const string PART_BHLPath = "PART_BHLPath"; //主要部分-下水平左  11
        private const string PART_BHRPath = "PART_BHRPath"; //主要部分-下水平右  12
        private const string PART_TDLPath = "PART_TDLPath"; //主要部分-上倾斜左  13
        private const string PART_TDRPath = "PART_TDRPath"; //主要部分-上倾斜右  14
        private const string PART_BDLPath = "PART_BDLPath"; //主要部分-下倾斜左  15
        private const string PART_BDRPath = "PART_BDRPath"; //主要部分-下倾斜右  16

        /// <summary>
        /// Describes the SixteenLeds to turn on for each character
        /// </summary>
        private static Dictionary<string, List<SixteenSegment>> characterLeds = new Dictionary<string, List<SixteenSegment>>
        {
            { " ", new List<SixteenSegment>() },
            { "A", new List<SixteenSegment> { SixteenSegment.THL, SixteenSegment.THR, SixteenSegment.TVL, SixteenSegment.TVR, SixteenSegment.BVL, SixteenSegment.BVR, SixteenSegment.MHL, SixteenSegment.MHR } },
            { "B", new List<SixteenSegment> { SixteenSegment.THL, SixteenSegment.THR, SixteenSegment.TVM, SixteenSegment.BVM, SixteenSegment.MHR, SixteenSegment.TVR, SixteenSegment.BVR, SixteenSegment.BHL, SixteenSegment.BHR } },
            { "C", new List<SixteenSegment> { SixteenSegment.THL, SixteenSegment.THR, SixteenSegment.BHL, SixteenSegment.BHR, SixteenSegment.TVL, SixteenSegment.BVL } },
            { "D", new List<SixteenSegment> { SixteenSegment.THL, SixteenSegment.THR, SixteenSegment.TVM, SixteenSegment.BVM, SixteenSegment.TVR, SixteenSegment.BVR, SixteenSegment.BHL, SixteenSegment.BHR } },
            { "E", new List<SixteenSegment> { SixteenSegment.THL, SixteenSegment.THR, SixteenSegment.BHL, SixteenSegment.BHR, SixteenSegment.TVL, SixteenSegment.BVL,  SixteenSegment.MHR, SixteenSegment.MHL } },
            { "F", new List<SixteenSegment> { SixteenSegment.THL, SixteenSegment.THR, SixteenSegment.TVL, SixteenSegment.BVL,  SixteenSegment.MHL } },
            { "G", new List<SixteenSegment> { SixteenSegment.THL, SixteenSegment.THR, SixteenSegment.BHL, SixteenSegment.BHR, SixteenSegment.TVL, SixteenSegment.BVL,  SixteenSegment.MHR, SixteenSegment.BVR } },
            { "H", new List<SixteenSegment> { SixteenSegment.TVL, SixteenSegment.TVR, SixteenSegment.BVL, SixteenSegment.BVR, SixteenSegment.MHL, SixteenSegment.MHR } },
            { "I", new List<SixteenSegment> { SixteenSegment.TVM, SixteenSegment.BVM } },
            { "J", new List<SixteenSegment> { SixteenSegment.BHL, SixteenSegment.BHR, SixteenSegment.BVL, SixteenSegment.BVR, SixteenSegment.TVR } },
            { "K", new List<SixteenSegment> { SixteenSegment.TVL, SixteenSegment.BVL, SixteenSegment.MHL, SixteenSegment.TDR, SixteenSegment.BDR } },
            { "L", new List<SixteenSegment> { SixteenSegment.BHL, SixteenSegment.BHR, SixteenSegment.TVL, SixteenSegment.BVL } },
            { "M", new List<SixteenSegment> { SixteenSegment.TVL, SixteenSegment.BVL, SixteenSegment.TVR, SixteenSegment.BVR, SixteenSegment.TDL, SixteenSegment.TDR } },
            { "N", new List<SixteenSegment> { SixteenSegment.TVL, SixteenSegment.BVL, SixteenSegment.TVR, SixteenSegment.BVR, SixteenSegment.TDL, SixteenSegment.BDR } },
            { "O", new List<SixteenSegment> { SixteenSegment.THL, SixteenSegment.THR, SixteenSegment.BHL, SixteenSegment.BHR, SixteenSegment.TVL, SixteenSegment.BVL, SixteenSegment.BVR, SixteenSegment.TVR } },
            { "P", new List<SixteenSegment> { SixteenSegment.THL, SixteenSegment.THR,  SixteenSegment.TVL, SixteenSegment.BVL, SixteenSegment.MHL, SixteenSegment.MHR, SixteenSegment.TVR } },
            { "Q", new List<SixteenSegment> { SixteenSegment.THL, SixteenSegment.THR, SixteenSegment.BHL, SixteenSegment.BHR, SixteenSegment.TVL, SixteenSegment.BVL, SixteenSegment.BVR, SixteenSegment.TVR, SixteenSegment.BDR } },
            { "U", new List<SixteenSegment> { SixteenSegment.BHL, SixteenSegment.BHR, SixteenSegment.TVL, SixteenSegment.BVL, SixteenSegment.BVR, SixteenSegment.TVR } },
            { "R", new List<SixteenSegment> { SixteenSegment.THL, SixteenSegment.THR, SixteenSegment.TVL, SixteenSegment.BVL, SixteenSegment.MHL, SixteenSegment.MHR, SixteenSegment.TVR, SixteenSegment.BDR } },
            { "S", new List<SixteenSegment> { SixteenSegment.THL, SixteenSegment.THR, SixteenSegment.BHL, SixteenSegment.BHR, SixteenSegment.TVL, SixteenSegment.BVR, SixteenSegment.MHR, SixteenSegment.MHL } },
            { "T", new List<SixteenSegment> { SixteenSegment.TVM, SixteenSegment.BVM, SixteenSegment.THL, SixteenSegment.THR } },
            { "V", new List<SixteenSegment> { SixteenSegment.TVL, SixteenSegment.BVL, SixteenSegment.BDL, SixteenSegment.TDR } },
            { "W", new List<SixteenSegment> { SixteenSegment.TVL, SixteenSegment.BVL, SixteenSegment.BDL, SixteenSegment.BDR, SixteenSegment.TVR, SixteenSegment.BVR } },
            { "X", new List<SixteenSegment> { SixteenSegment.TDL, SixteenSegment.TDR, SixteenSegment.BDL, SixteenSegment.BDR } },
            { "Y", new List<SixteenSegment> { SixteenSegment.TDL, SixteenSegment.TDR, SixteenSegment.BVM } },
            { "Z", new List<SixteenSegment> { SixteenSegment.TDR, SixteenSegment.BDL, SixteenSegment.THL, SixteenSegment.THR, SixteenSegment.BHL, SixteenSegment.BHR } },
            { "0", new List<SixteenSegment> { SixteenSegment.THL, SixteenSegment.THR, SixteenSegment.BHL, SixteenSegment.BHR, SixteenSegment.TVL, SixteenSegment.BVL, SixteenSegment.BVR, SixteenSegment.TVR } },
            { "1", new List<SixteenSegment> { SixteenSegment.TVR, SixteenSegment.BVR } },
            { "2", new List<SixteenSegment> { SixteenSegment.THL, SixteenSegment.THR, SixteenSegment.BHL, SixteenSegment.BHR, SixteenSegment.BVL, SixteenSegment.MHR, SixteenSegment.MHL, SixteenSegment.TVR } },
            { "3", new List<SixteenSegment> { SixteenSegment.THL, SixteenSegment.THR, SixteenSegment.BHL, SixteenSegment.BHR, SixteenSegment.BVR, SixteenSegment.MHR, SixteenSegment.MHL, SixteenSegment.TVR, SixteenSegment.MHR } },
            { "4", new List<SixteenSegment> { SixteenSegment.TVL, SixteenSegment.MHR, SixteenSegment.MHL, SixteenSegment.TVR, SixteenSegment.BVR } },

            { "5", new List<SixteenSegment> { SixteenSegment.THL, SixteenSegment.THR, SixteenSegment.BHL, SixteenSegment.BDR, SixteenSegment.BHR, SixteenSegment.MHL, SixteenSegment.TVL  } },

            { "6", new List<SixteenSegment> { SixteenSegment.THL, SixteenSegment.THR, SixteenSegment.BHL, SixteenSegment.BHR, SixteenSegment.TVL, SixteenSegment.BVL,  SixteenSegment.MHR, SixteenSegment.MHL,  SixteenSegment.BVR } },
            { "7", new List<SixteenSegment> { SixteenSegment.THL, SixteenSegment.THR, SixteenSegment.TVR, SixteenSegment.BVR } },
            { "8", new List<SixteenSegment> { SixteenSegment.THL, SixteenSegment.THR, SixteenSegment.BHL, SixteenSegment.BHR, SixteenSegment.TVL, SixteenSegment.BVL,  SixteenSegment.MHR, SixteenSegment.MHL, SixteenSegment.TVR, SixteenSegment.BVR } },
            { "9", new List<SixteenSegment> { SixteenSegment.THL, SixteenSegment.THR, SixteenSegment.BHL, SixteenSegment.BHR, SixteenSegment.TVL, SixteenSegment.MHR, SixteenSegment.MHL, SixteenSegment.TVR, SixteenSegment.BVR } },
        };

        #endregion Constants

        #region Members

        private Grid gridRoot;
        private Path pathTHL;
        private Path pathTHR;
        private Path pathTVL;
        private Path pathTVM;
        private Path pathTVR;
        private Path pathMHL;
        private Path pathMHR;
        private Path pathBVL;
        private Path pathBVM;
        private Path pathBVR;
        private Path pathBHL;
        private Path pathBHR;
        private Path pathTDL;
        private Path pathTDR;
        private Path pathBDL;
        private Path pathBDR;

        /// <summary>
        /// Has initialization completed and can we animate
        /// </summary>
        private bool hasInitialized = false;

        /// <summary>
        /// Stores a map to paths from segment names
        /// </summary>
        private Dictionary<SixteenSegment, Path> leds = new Dictionary<SixteenSegment, Path>();

        #endregion Members

        #region Constructors

        /// <summary>
        ///
        /// </summary>
        static SixteenSegmentDigit()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(SixteenSegmentDigit), new FrameworkPropertyMetadata(typeof(SixteenSegmentDigit)));
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            gridRoot = GetTemplateChild(PART_RootGrid) as Grid;
            pathTHL = GetTemplateChild(PART_THLPath) as Path;
            pathTHR = GetTemplateChild(PART_THRPath) as Path;
            pathTVL = GetTemplateChild(PART_TVLPath) as Path;
            pathTVM = GetTemplateChild(PART_TVMPath) as Path;
            pathTVR = GetTemplateChild(PART_TVRPath) as Path;
            pathMHL = GetTemplateChild(PART_MHLPath) as Path;
            pathMHR = GetTemplateChild(PART_MHRPath) as Path;
            pathBVL = GetTemplateChild(PART_BVLPath) as Path;
            pathBVM = GetTemplateChild(PART_BVMPath) as Path;
            pathBVR = GetTemplateChild(PART_BVRPath) as Path;
            pathBHL = GetTemplateChild(PART_BHLPath) as Path;
            pathBHR = GetTemplateChild(PART_BHRPath) as Path;
            pathTDL = GetTemplateChild(PART_TDLPath) as Path;
            pathTDR = GetTemplateChild(PART_TDRPath) as Path;
            pathBDL = GetTemplateChild(PART_BDLPath) as Path;
            pathBDR = GetTemplateChild(PART_BDRPath) as Path;
            this.Loaded -= SixteenSegmentLED_Loaded;
            this.Loaded += SixteenSegmentLED_Loaded;
        }

        #endregion Constructors

        #region Properties

        #region DisplayCharacter

        /// <summary>
        /// The dependancy property for the DisplayCharacter property
        /// </summary>
        public static readonly DependencyProperty DisplayCharacterProperty =
            DependencyProperty.Register("DisplayCharacter", typeof(string), typeof(SixteenSegmentDigit), new PropertyMetadata("0", DisplayCharacterPropertyChanged));

        /// <summary>
        /// Gets or sets the current Display char 0..9 A..Z
        /// </summary>
        public string DisplayCharacter
        {
            get { return (string)GetValue(DisplayCharacterProperty); }
            set { SetValue(DisplayCharacterProperty, value); }
        }

        /// <summary>
        /// Property changed, show the new value
        /// </summary>
        /// <param name="dependancy">The dependancy object for the property</param>
        /// <param name="args">The <see cref="System.Windows.DependencyPropertyChangedEventArgs"/> instance containing the event data.</param>
        private static void DisplayCharacterPropertyChanged(DependencyObject dependancy, DependencyPropertyChangedEventArgs args)
        {
            SixteenSegmentDigit instance = dependancy as SixteenSegmentDigit;
            if (instance != null)
            {
                instance.Animate();
            }
        }

        #endregion DisplayCharacter

        #region LedOffColor

        /// <summary>
        /// The dependancy property for the LedOffColor property
        /// </summary>
        public static readonly DependencyProperty LedOffColorProperty =
            DependencyProperty.Register("LedOffColor", typeof(Color), typeof(SixteenSegmentDigit), new PropertyMetadata(Color.FromArgb(51, 97, 75, 141), ColorPropertyChanged));

        /// <summary>
        /// Gets or sets the  off color of the led
        /// </summary>
        public Color LedOffColor
        {
            get { return (Color)GetValue(LedOffColorProperty); }
            set { SetValue(LedOffColorProperty, value); }
        }

        /// <summary>
        /// Our Colour property has changed
        /// </summary>
        /// <param name="dependancy">The dependancy.</param>
        /// <param name="args">The <see cref="System.Windows.DependencyPropertyChangedEventArgs"/> instance containing the event data.</param>
        private static void ColorPropertyChanged(DependencyObject dependancy, DependencyPropertyChangedEventArgs args)
        {
            SixteenSegmentDigit instance = dependancy as SixteenSegmentDigit;

            if (instance != null)
            {
                instance.Animate();
            }
        }

        #endregion LedOffColor

        #region LedOnColor

        /// <summary>
        /// The dependancy property for the LedOnColor property
        /// </summary>
        public static readonly DependencyProperty LedOnColorProperty =
            DependencyProperty.Register("LedOnColor", typeof(Color), typeof(SixteenSegmentDigit), new PropertyMetadata(Colors.Green, ColorPropertyChanged));

        /// <summary>
        /// Gets or sets the on colour of the led
        /// </summary>
        public Color LedOnColor
        {
            get { return (Color)GetValue(LedOnColorProperty); }
            set { SetValue(LedOnColorProperty, value); }
        }

        #endregion LedOnColor

        #endregion Properties

        #region Methods

        /// <summary>
        /// Handles the Loaded event of the SixteenSegmentLED control. Once#loaded we display the char
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        private void SixteenSegmentLED_Loaded(object sender, RoutedEventArgs e)
        {
            if (!this.hasInitialized)
            {
                this.hasInitialized = true;
                this.StoreLedInformation();
            }

            this.Animate();
        }

        /// <summary>
        /// Display the control according the the current value
        /// </summary>
        private void Animate()
        {
            this.SetAllLedsOff();
            this.SetRequiresLedsON();
        }

        /// <summary>
        /// Sets all leds off.
        /// </summary>
        private void SetAllLedsOff()
        {
            if (hasInitialized)
            {
                foreach (Path path in this.leds.Values)
                {
                    path.Fill = new SolidColorBrush(this.LedOffColor);
                }
            }
        }

        /// <summary>
        /// Sets the required leds ON.
        /// </summary>
        private void SetRequiresLedsON()
        {
            if (hasInitialized)
            {
                if (this.leds.Count == 0 || String.IsNullOrEmpty(this.DisplayCharacter) || this.DisplayCharacter == " ")
                {
                    return;
                }

                if (this.DisplayCharacter.Length > 1)
                {
                    this.ShowError();
                }

                if (characterLeds.ContainsKey(this.DisplayCharacter.ToUpper(CultureInfo.CurrentCulture)))
                {
                    var leds = characterLeds[this.DisplayCharacter.ToUpper(CultureInfo.CurrentCulture)];
                    foreach (SixteenSegment led in leds)
                    {
                        this.leds[led].Fill = new SolidColorBrush(this.LedOnColor);
                    }
                }
            }
        }

        /// <summary>
        /// We show an error by turning everything on!
        /// </summary>
        private void ShowError()
        {
            if (hasInitialized)
            {
                foreach (Path path in this.leds.Values)
                {
                    path.Fill = new SolidColorBrush(this.LedOnColor);
                }
            }
        }

        /// <summary>
        /// Stores the led information.
        /// </summary>
        private void StoreLedInformation()
        {
            this.leds.Clear();
            this.leds.Add(SixteenSegment.BDL, pathBDL);
            this.leds.Add(SixteenSegment.BDR, pathBDR);
            this.leds.Add(SixteenSegment.BHL, pathBHL);
            this.leds.Add(SixteenSegment.BHR, pathBHR);
            this.leds.Add(SixteenSegment.BVL, pathBVL);
            this.leds.Add(SixteenSegment.BVM, pathBVM);
            this.leds.Add(SixteenSegment.BVR, pathBVR);
            this.leds.Add(SixteenSegment.MHL, pathMHL);
            this.leds.Add(SixteenSegment.MHR, pathMHR);
            this.leds.Add(SixteenSegment.TDL, pathTDL);
            this.leds.Add(SixteenSegment.TDR, pathTDR);
            this.leds.Add(SixteenSegment.THL, pathTHL);
            this.leds.Add(SixteenSegment.THR, pathTHR);
            this.leds.Add(SixteenSegment.TVL, pathTVL);
            this.leds.Add(SixteenSegment.TVM, pathTVM);
            this.leds.Add(SixteenSegment.TVR, pathTVR);
        }

        #endregion Methods
    }
}